package org.intelligentsia.temporal;

import junit.framework.Assert;
import junit.framework.TestCase;

/**
 * 
 * * @author <a href="mailto:jguibert@intelligents-ia.com" >Jerome Guibert</a>
 * 
 */
public class TemporalContainerTestCase extends TestCase {
	private TemporalContainer<StringTemporal>	container	= null;

	@Override
	protected void setUp() throws Exception {
		super.setUp();
		container = new TemporalContainer<StringTemporal>(new TemporalFactory<StringTemporal>() {

			@Override
			public StringTemporal newInstance(final StringTemporal result) {
				return new StringTemporal(result.validity, result.value);
			}
		});
		// set of data
		container.add(getA());
		container.add(getB());
		container.add(getC());
	}

	public void testRetrieve() {
		Assert.assertEquals(getA(), container.getTemporal(-1l));
		Assert.assertEquals(getA(), container.getTemporal(0l));
		Assert.assertEquals(getB(), container.getTemporal(1l));
		Assert.assertEquals(getB(), container.getTemporal(2l));
		Assert.assertEquals(getB(), container.getTemporal(9l));
		Assert.assertEquals(getC(), container.getTemporal(20l));
		Assert.assertNull(container.getTemporal(200000l + 1l));
	}

	public void testRetrieveUpdate() {
		final StringTemporal value = container.getTemporal(2l);
		Assert.assertEquals(getB(), value);
		value.setValue("B PRIME");
		// not in B.validity
		Assert.assertFalse(container.update(value, -1l));
		// not in B.validity strict
		Assert.assertFalse(container.update(value, 1l));
		// ok for update
		Assert.assertTrue(container.update(value, 5l));
		Assert.assertEquals(getUpdatedB(), container.getTemporal(2l));
		Assert.assertEquals(getNewB(), container.getTemporal(5l));
	}

	public void testOverLap() {
		try {
			container.add(new StringTemporal(new TransactionTime(-5l, 0l), "overlap value"));
			Assert.fail("TransactionTime over lap other");
		} catch (final IllegalStateException e) {
		}
	}

	private StringTemporal getA() {
		return new StringTemporal(new TransactionTime(Long.MIN_VALUE, 0l), "A");
	}

	private StringTemporal getB() {
		return new StringTemporal(new TransactionTime(1l, 9l), "B");
	}

	private StringTemporal getUpdatedB() {
		return new StringTemporal(new TransactionTime(1l, 4l), "B");
	}

	private StringTemporal getNewB() {
		return new StringTemporal(new TransactionTime(5l, 9l), "B PRIME");
	}

	private StringTemporal getC() {
		return new StringTemporal(new TransactionTime(10l, 200000l), "C");
	}

	/**
	 * Testing Class.
	 * 
	 * @author <a href="mailto:jguibert@intelligents-ia.com" >Jerome Guibert</a>
	 * 
	 */
	public class StringTemporal implements Temporal {

		private TransactionTime	validity;
		private String			value;

		public StringTemporal(final String value) {
			this(new TransactionTime(), value);
		}

		public StringTemporal(final TransactionTime validity, final String value) {
			super();
			this.validity = validity;
			this.value = value;
		}

		@Override
		public TransactionTime getTransactionTime() {
			return validity;
		}

		@Override
		public void setTransactionTime(final TransactionTime validity) {
			this.validity = validity;

		}

		/**
		 * Immutable.
		 * 
		 * @return
		 */
		public String getValue() {
			return new String(value);
		}

		public void setValue(final String string) {
			value = string;
		}

		@Override
		public String toString() {
			return "StringTemporal [validity=" + validity + ", value=" + value + "]";
		}

		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + getOuterType().hashCode();
			result = prime * result + ((validity == null) ? 0 : validity.hashCode());
			result = prime * result + ((value == null) ? 0 : value.hashCode());
			return result;
		}

		@Override
		public boolean equals(final Object obj) {
			if (this == obj) {
				return true;
			}
			if (obj == null) {
				return false;
			}
			if (getClass() != obj.getClass()) {
				return false;
			}
			final StringTemporal other = (StringTemporal) obj;
			if (!getOuterType().equals(other.getOuterType())) {
				return false;
			}
			if (validity == null) {
				if (other.validity != null) {
					return false;
				}
			} else if (!validity.equals(other.validity)) {
				return false;
			}
			if (value == null) {
				if (other.value != null) {
					return false;
				}
			} else if (!value.equals(other.value)) {
				return false;
			}
			return true;
		}

		private TemporalContainerTestCase getOuterType() {
			return TemporalContainerTestCase.this;
		}

	}
}
